package backend.db.listeners;

import java.sql.SQLException;
import java.sql.Statement;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import logs.LogFactory;

import org.apache.log4j.Logger;

import backend.ConnectionPool;
import backend.Util;
import backend.db.ConnectionManager;
import backend.db.ORM;
import backend.db.Table;
import backend.db.Tables;

/**
 * Application Lifecycle Listener implementation class DatabaseInitiator
 */
public class DatabaseInitiator implements ServletContextListener {
  private static final Logger logger = LogFactory.getLog(DatabaseInitiator.class);
  
  /**
   * @see ServletContextListener#contextInitialized(ServletContextEvent)
   */
  @Override public void contextInitialized(final ServletContextEvent evt) {
    logger.debug("contextInitialized");
    final ServletContext servletContext = evt.getServletContext();
    final String url = servletContext.getInitParameter("database.url");
    final String username = servletContext.getInitParameter("database.username");
    final String password = servletContext.getInitParameter("database.password");
    final String driver = servletContext.getInitParameter("database.driver");
    loadDriver(driver);
    try {
      ConnectionPool.initConnectionPool(url, username, password);
    } catch (final SQLException e) {
      logger.fatal("couldn't initialize connection pool", e);
      throw new RuntimeException("couldn't initialize connection pool", e);
    }
    final ConnectionManager cm = ORM.cp.captureConnection();
    try {
      createTables(cm);
    } finally {
      ORM.cp.releaseConnection(cm);
    }
  }
  
  /**
   * @see ServletContextListener#contextDestroyed(ServletContextEvent)
   */
  @Override public void contextDestroyed(final ServletContextEvent evt) {
    logger.debug("contextDestroyed");
    // final ConnectionManager cm = ORM.cp.captureConnection();
    // try {
    // dropTables(cm); // This is currently unnecessary.
    // } finally {
    // ORM.cp.releaseConnection(cm);
    // }
    ConnectionPool.destroyPool();
  }
  
  private void loadDriver(final String driver) {
    try {
      Class.forName(driver);
    } catch (final ClassNotFoundException e) {
      logger.fatal("unable to load driver", e);
      throw new RuntimeException("unable to load driver", e);
    }
  }
  
  private void createTables(final ConnectionManager cm) {
    Statement stmt = null;
    try {
      stmt = cm.createStatement();
      for (final Table t : Tables.tables)
        stmt.executeUpdate(t.getCreateSQL());
    } catch (final SQLException e) {
      logger.fatal("error creating tables", e);
      throw new RuntimeException("error creating tables", e);
    } finally {
      Util.tryClose(stmt);
    }
  }
  
  @SuppressWarnings("unused") private void dropTables(final ConnectionManager cm) {
    Statement stmt = null;
    try {
      stmt = cm.createStatement();
      for (final Table t : Tables.tables)
        stmt.executeUpdate(t.getCreateSQL());
    } catch (final SQLException e) {
      logger.error("error when deleting tables", e);
      // we don't throw here because the servlet context is closing anyways
    } finally {
      Util.tryClose(stmt);
    }
  }
}
